/**
 *  Document   : HotelAndRoomManagement
 *  Created on : 17 juil. 2008, 15:49:59
 *  Author     : Rivo
 */
package gla.centralhotel.business;

import gla.centralhotel.dao.interfaces.IHotelDAO;
import gla.centralhotel.dao.interfaces.IPriceDAO;
import gla.centralhotel.dao.interfaces.IRoomDAO;
import gla.centralhotel.exception.CollectionRetrieverException;
import gla.centralhotel.exception.HotelRoomNumberException;
import gla.centralhotel.exception.IllegalPeriodException;
import gla.centralhotel.exception.IllegalPriceException;
import gla.centralhotel.exception.IllegalRoomNumberException;
import gla.centralhotel.exception.SubscriptionManagementException;
import gla.centralhotel.exception.TooLongTextException;
import gla.centralhotel.model.Hotel;
import gla.centralhotel.model.Manager;
import gla.centralhotel.model.Price;
import gla.centralhotel.model.Room;
import gla.centralhotel.model.RoomType;
import gla.centralhotel.model.Zipcode;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;

@Stateless
public class HotelAndRoomManagement implements IHotelAndRoomManagement {

    @EJB
    private IPriceDAO priceDAO;
    @EJB
    private IRoomDAO roomDAO;
    @EJB
    private IHotelDAO hotelDAO;

    /**
     * retourne la liste de tous les hotel
     * @return
     */
    public ArrayList<Hotel> getHotelList()
    {
        ArrayList<Hotel> alh = new ArrayList<Hotel>( this.hotelDAO.findAll() );
        return alh;
    } 
    
    /**
     * retourne la liste des hotel par ville
     * @param zipcodeId
     * @return
     */
    public ArrayList<Hotel> getHotelListByZipcode(Integer zipcodeId)
    {
        ArrayList<Hotel> alh = new ArrayList<Hotel>();
        try
        {
            alh = this.hotelDAO.getHotelByZipcode(new Zipcode(zipcodeId)); 
        }
        catch (CollectionRetrieverException ex)
        {
            Logger.getLogger(HotelAndRoomManagement.class.getName()).log(Level.SEVERE, null, ex);
        }
        return alh;
    } 
    
    /**
     * Enregistre l'hotel contenant une refManager
     * @param hotel
     * @return
     */
    public Hotel saveHotelSubscription(Hotel hotel) throws SubscriptionManagementException, TooLongTextException {
        try {
            return hotelDAO.saveHotel(hotel);
        } catch (SubscriptionManagementException ex) {
            Logger.getLogger(SubscriptionManagement.class.getName()).log(Level.SEVERE, null, ex);
            throw new SubscriptionManagementException("Erreur grave, enregistrement d'hotel sans manager!!!");
        } catch(TooLongTextException e){
            throw new TooLongTextException("Description ou service trop long 255 caractères max !!");
        }
    }

    /**
     * Enregistre l'hotel avec une refManager en params
     * @param hotel
     * @param manager
     * @return
     */
    public Hotel saveHotelSubscription(Hotel hotel, Manager manager) throws SubscriptionManagementException, TooLongTextException{
        hotel.setRefManager(manager);
        try {
            return hotelDAO.saveHotel(hotel);
        } catch (SubscriptionManagementException ex) {
            Logger.getLogger(SubscriptionManagement.class.getName()).log(Level.SEVERE, null, ex);
            throw new SubscriptionManagementException("Erreur grave, enregistrement d'hotel sans manager!!!");
        }catch(TooLongTextException e){
            throw new TooLongTextException("Description ou service trop long 255 caractères max !!");
        }
    }

    /**
     * Le parametre "room" doit etre initialiser par les params "hotel" et type
     * Une chambre : id + numéro de chambre
     * @param hotel
     * @param room
     * @param type
     * @return
     */
    public Room addRoomToHotel(Hotel hotel, Room room, RoomType type) throws HotelRoomNumberException {
        room.setRefHotel(hotel);
        room.setRefRoomType(type);
        try {
            return roomDAO.saveRoom(room);
        } catch (IllegalRoomNumberException ex) {
            Logger.getLogger(HotelAndRoomManagement.class.getName()).log(Level.SEVERE, null, ex);
            throw new HotelRoomNumberException("Le numéro de la chambre existe déjà!!");
        }
    }

    /**
     * Le parametre "room" contient tous les ref qu'il faut
     * refHotel et refRoomType
     * Une chambre : id + numéro de chambre
     * @param room
     * @return
     */
    public Room addRoomToHotel(Room room) throws HotelRoomNumberException {
        try {
            return roomDAO.saveRoom(room);
        } catch (IllegalRoomNumberException ex) {
            Logger.getLogger(HotelAndRoomManagement.class.getName()).log(Level.SEVERE, null, ex);
            throw new HotelRoomNumberException("Le numéro de la chambre existe déjà!!");
        }
    }

    /**
     * Cree le prix de la chambre avec une refRoom primitif
     * Période et le prix en float
     * @param refRoom
     * @param start
     * @param end
     * @param price
     * @return
     */
    public Price setPriceToRoom(Integer refRoom, Date start, Date end, Float price) throws IllegalPriceException, IllegalPeriodException {
        if ((start.before(end) && end.after(new Date())) || (start.equals(end) && start.after(new Date()))) {
            Price newPrice = new Price();
            Room room = roomDAO.find_(refRoom);
            newPrice.setPeriodStart(start);
            newPrice.setPeriodEnd(end);
            newPrice.setPrice(price);
            newPrice.setRefRoom(room);
            try {
                return priceDAO.savePriceForRoom(newPrice);
            } catch (IllegalPriceException ex) {
                Logger.getLogger(HotelAndRoomManagement.class.getName()).log(Level.SEVERE, null, ex);
                throw new IllegalPriceException("Erreur grave il y a plusieurs prix " +
                        "sur une même période pour la même chambre");
            }
        } else {
            throw new IllegalPeriodException("La période fournie est invalide");
        }
    }

    /**
     * Cree le prix (unitaire)de la chambre "room" avec en params la période et le prix en float
     * @param room
     * @param start
     * @param end
     * @param price
     * @return
     */
    public Price setPriceToRoom(Room room, Date start, Date end, Float price) throws IllegalPriceException, IllegalPeriodException {
        if (start.before(end) || start.equals(end) ) {
            ArrayList<Price> prices;
            boolean isPriceSet = false;
            try {
                prices = priceDAO.getAllPriceByRoom(room);
                Iterator<Price> iter = prices.iterator();
                while (iter.hasNext()) {
                    Price tmp = iter.next();
                    if (tmp.getPeriodStart().before(start) && tmp.getPeriodEnd().after(start)) {
                        isPriceSet = true;
                    }
                }
                if (isPriceSet) {
                    throw new IllegalPeriodException("Il y a déjà un prix sur cette période !");
                } else {
                    while (iter.hasNext()) {
                        Price tmp = iter.next();
                        if (tmp.getPeriodStart().before(end) && tmp.getPeriodEnd().after(end)) {
                            isPriceSet = true;
                        }
                    }
                    if (isPriceSet) {
                        throw new IllegalPeriodException("Il y a déjà un prix sur cette période !");
                    } else {
                        Price newPrice = new Price();
                        newPrice.setPeriodStart(start);
                        newPrice.setPeriodEnd(end);
                        newPrice.setPrice(price);
                        newPrice.setRefRoom(room);
                        try {
                            return priceDAO.savePriceForRoom(newPrice);
                        } catch (IllegalPriceException ex) {
                            Logger.getLogger(HotelAndRoomManagement.class.getName()).log(Level.SEVERE, null, ex);
                            throw new IllegalPriceException("Erreur grave il y a plusieurs prix " +
                                    "sur une même période pour la même chambre");
                        }

                    }
                }
            } catch (CollectionRetrieverException ex) {
                ex.printStackTrace();
                return null;
            }
        }else{
            throw new IllegalPeriodException("Mauvaise période !");
        }
    }
    
    public void deletePrice(Price price){
        priceDAO.remove(price);
    }
    

}
